package baseFx.common.lock.redis;

import baseFx.common.AutoCloseable;
import baseFx.common.concurrent.Task;
import baseFx.common.lock.AbortTimeoutException;
import baseFx.common.lock.Lockspace;
import baseFx.common.lock.LockspaceException;
import baseFx.common.utils.FxDate;
import baseFx.common.utils.RandomUtils;
import redis.clients.jedis.JedisPool;

public class RedisLockspace implements Lockspace {
    private JedisPool pool;

    public static void heartbeat(JedisPool pool) {
        ConcurLocker.heartbeat(pool);
    }

    public RedisLockspace(JedisPool pool) {
        this.pool = pool;
    }

    @Override
    public AutoCloseable queueLock(String key, Integer abortTimeout) throws AbortTimeoutException {
        if (abortTimeout == null) {
            abortTimeout = Integer.MAX_VALUE;
        }
        long exp = System.currentTimeMillis() + FxDate.SECONDS * abortTimeout.longValue();
        SimpleLocker locker = new SimpleLocker(pool);
        while (locker.lock(key) == false) {
            if (exp < System.currentTimeMillis()) {
                locker.close();
                throw new AbortTimeoutException(key);
            }
            Task.delay(Long.parseLong(RandomUtils.numByRange(200, 1000)));
        }
        return locker;
    }

    @Override
    public AutoCloseable exLock(String key) throws LockspaceException {
        SimpleLocker locker = new SimpleLocker(pool);
        if (locker.lock(key) == false) {
            locker.close();
            throw new LockspaceException(key + " 已锁定");
        }
        return locker;
    }

    @Override
    public AutoCloseable concurrentLock(String key, int max, Integer abortTimeout) throws AbortTimeoutException {
        if (abortTimeout == null) {
            abortTimeout = Integer.MAX_VALUE;
        }
        long exp = System.currentTimeMillis() + FxDate.SECONDS * abortTimeout.longValue();
        ConcurLocker locker = new ConcurLocker(pool);
        while (locker.lock(key, max) == false) {
            if (exp < System.currentTimeMillis()) {
                locker.close();
                throw new AbortTimeoutException(key);
            }
            Task.delay(Long.parseLong(RandomUtils.numByRange(200, 1000)));
        }
        return locker;
    }
}
